use serde::{Deserialize, Serialize};
use serde_json::{json, Value};

use crate::wechat::cp::constants::ACCESS_TOKEN;
use crate::wechat::cp::method::{CpUserMethod, WechatCpMethod};
use crate::wechat::cp::model::WechatCpUserExternalContactInfo;
use crate::{
    request::RequestType, session::SessionStore, LabradorResult, WechatCommonResponse,
    WechatCpTpClient, WechatCpUserInfo,
};

/// 部门管理
#[derive(Debug, Clone)]
pub struct WechatCpTpUser<'a, T: SessionStore> {
    client: &'a WechatCpTpClient<T>,
}

#[allow(unused)]
impl<'a, T: SessionStore> WechatCpTpUser<'a, T> {
    #[inline]
    pub fn new(client: &WechatCpTpClient<T>) -> WechatCpTpUser<T> {
        WechatCpTpUser { client }
    }

    /// <pre>
    ///   用在二次验证的时候.
    ///   企业在员工验证成功后，调用本方法告诉企业号平台该员工关注成功。
    /// </pre>
    pub async fn authenticate(&self, user_id: &str) -> LabradorResult<WechatCommonResponse> {
        self.client
            .get(
                WechatCpMethod::User(CpUserMethod::AuthSuccess(user_id.to_string())),
                vec![],
                RequestType::Json,
            )
            .await?
            .json::<WechatCommonResponse>()
    }

    /// <pre>
    /// 获取部门成员(详情).
    ///
    /// http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98.28.E8.AF.A6.E6.83.85.29
    /// </pre>
    pub async fn list_by_department(
        &self,
        depart_id: i64,
        fetch_child: Option<bool>,
        status: Option<i32>,
        corp_id: &str,
    ) -> LabradorResult<Vec<WechatCpUserInfo>> {
        let access_token = self.client.get_access_token(corp_id);
        let mut query = vec![(ACCESS_TOKEN.to_string(), access_token)];
        if let Some(fetch_child) = fetch_child {
            query.push(("fetch_child".to_string(), fetch_child.to_string()));
        }
        if let Some(status) = status {
            query.push(("status".to_string(), status.to_string()));
        } else {
            query.push(("status".to_string(), "0".to_string()));
        }
        let v = self
            .client
            .get(WechatCpMethod::User(CpUserMethod::List(depart_id)), query, RequestType::Json)
            .await?
            .json::<Value>()?;
        WechatCommonResponse::parse::<Vec<WechatCpUserInfo>>(v)
    }

    /// <pre>
    /// 获取部门成员.
    ///
    /// http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98
    /// </pre>
    pub async fn list_simple_by_department(
        &self,
        depart_id: i64,
        fetch_child: Option<bool>,
        status: Option<i32>,
    ) -> LabradorResult<Vec<WechatCpUserInfo>> {
        let mut query = vec![];
        if let Some(fetch_child) = fetch_child {
            query.push(("fetch_child".to_string(), fetch_child.to_string()));
        }
        if let Some(status) = status {
            query.push(("status".to_string(), status.to_string()));
        } else {
            query.push(("status".to_string(), "0".to_string()));
        }
        let v = self
            .client
            .get(
                WechatCpMethod::User(CpUserMethod::SimpleList(depart_id)),
                query,
                RequestType::Json,
            )
            .await?
            .json::<Value>()?;
        WechatCommonResponse::parse::<Vec<WechatCpUserInfo>>(v)
    }

    /// <pre>
    /// 新建用户
    /// </pre>
    pub async fn create(&self, req: WechatCpUserInfo) -> LabradorResult<WechatCommonResponse> {
        self.client
            .post(WechatCpMethod::User(CpUserMethod::Create), vec![], req, RequestType::Json)
            .await?
            .json::<WechatCommonResponse>()
    }

    /// <pre>
    /// 更新用户
    /// </pre>
    pub async fn update(&self, req: WechatCpUserInfo) -> LabradorResult<WechatCommonResponse> {
        self.client
            .post(WechatCpMethod::User(CpUserMethod::Update), vec![], req, RequestType::Json)
            .await?
            .json::<WechatCommonResponse>()
    }

    /// <pre>
    /// 删除用户/批量删除成员.
    /// http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E6.89.B9.E9.87.8F.E5.88.A0.E9.99.A4.E6.88.90.E5.91.98
    /// </pre>
    pub async fn delete(&self, user_ids: Vec<&str>) -> LabradorResult<WechatCommonResponse> {
        if user_ids.len() == 1 {
            self.client
                .get(
                    WechatCpMethod::User(CpUserMethod::Delete(user_ids[0].to_string())),
                    vec![],
                    RequestType::Json,
                )
                .await?
                .json::<WechatCommonResponse>()
        } else {
            self.client
                .post(
                    WechatCpMethod::User(CpUserMethod::BatchDelete),
                    vec![],
                    json!({"useridlist": user_ids}),
                    RequestType::Json,
                )
                .await?
                .json::<WechatCommonResponse>()
        }
    }

    /// <pre>
    /// 获取用户
    /// </pre>
    pub async fn get_by_id(&self, userid: &str, corp_id: &str) -> LabradorResult<WechatCpUserInfo> {
        let access_token = self.client.get_access_token(corp_id);
        let query = vec![(ACCESS_TOKEN.to_string(), access_token)];
        let v = self
            .client
            .get(
                WechatCpMethod::User(CpUserMethod::Get(userid.to_string())),
                query,
                RequestType::Json,
            )
            .await?
            .json::<Value>()?;
        WechatCommonResponse::parse::<WechatCpUserInfo>(v)
    }

    /// <pre>
    /// 邀请成员.
    /// 企业可通过接口批量邀请成员使用企业微信，邀请后将通过短信或邮件下发通知。
    /// 请求方式：POST（HTTPS）
    /// 请求地址： https://qyapi.weixin.qq.com/cgi-bin/batch/invite?access_token=ACCESS_TOKEN
    /// 文档地址：https://work.weixin.qq.com/api/doc#12543
    /// </pre>
    pub async fn invite(
        &self,
        userids: Vec<&str>,
        party_ids: Vec<&str>,
        tag_ids: Vec<&str>,
    ) -> LabradorResult<WxCpTpInviteResponse> {
        let req = json!({
            "user": userids,
            "party": party_ids,
            "tag": tag_ids,
        });
        let v = self
            .client
            .post(WechatCpMethod::User(CpUserMethod::Invite), vec![], req, RequestType::Json)
            .await?
            .json::<Value>()?;
        WechatCommonResponse::parse::<WxCpTpInviteResponse>(v)
    }

    /// <pre>
    ///  userid转openid.
    ///  该接口使用场景为微信支付、微信红包和企业转账。
    ///
    /// 在使用微信支付的功能时，需要自行将企业微信的userid转成openid。
    /// 在使用微信红包功能时，需要将应用id和userid转成appid和openid才能使用。
    /// 注：需要成员使用微信登录企业微信或者关注微信插件才能转成openid
    ///
    /// 文档地址：https://work.weixin.qq.com/api/doc#11279
    /// </pre>
    pub async fn userid_2_openid(
        &self,
        userid: &str,
        agent_id: i32,
    ) -> LabradorResult<WxCpTpUseridToOpenidResponse> {
        let req = json!({
            "userid": userid,
            "agentid": agent_id,
        });
        let v = self
            .client
            .post(
                WechatCpMethod::User(CpUserMethod::ConvertToOpenid),
                vec![],
                req,
                RequestType::Json,
            )
            .await?
            .json::<Value>()?;
        WechatCommonResponse::parse::<WxCpTpUseridToOpenidResponse>(v)
    }

    /// <pre>
    /// openid转userid.
    ///
    /// 该接口主要应用于使用微信支付、微信红包和企业转账之后的结果查询。
    /// 开发者需要知道某个结果事件的openid对应企业微信内成员的信息时，可以通过调用该接口进行转换查询。
    /// 权限说明：
    /// 管理组需对openid对应的企业微信成员有查看权限。
    ///
    /// 文档地址：https://work.weixin.qq.com/api/doc#11279
    /// </pre>
    pub async fn openid_2_userid(&self, openid: &str) -> LabradorResult<String> {
        let req = json!({
            "openid": openid,
        });
        let v = self
            .client
            .post(
                WechatCpMethod::User(CpUserMethod::ConvertToUserid),
                vec![],
                req,
                RequestType::Json,
            )
            .await?
            .json::<Value>()?;
        let v = WechatCommonResponse::parse::<Value>(v)?;
        let userid = v["userid"].as_str().unwrap_or_default();
        Ok(userid.to_string())
    }

    /// <pre>
    ///
    /// 通过手机号获取其所对应的userid。
    ///
    /// 请求方式：POST（HTTPS）
    /// 请求地址：https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token=ACCESS_TOKEN
    ///
    /// 文档地址：https://work.weixin.qq.com/api/doc#90001/90143/91693
    /// </pre>
    pub async fn get_userid(&self, mobile: &str) -> LabradorResult<String> {
        let req = json!({
            "mobile": mobile,
        });
        let v = self
            .client
            .post(WechatCpMethod::User(CpUserMethod::GetUserid), vec![], req, RequestType::Json)
            .await?
            .json::<Value>()?;
        let v = WechatCommonResponse::parse::<Value>(v)?;
        let userid = v["userid"].as_str().unwrap_or_default();
        Ok(userid.to_string())
    }

    /// 获取外部联系人详情.
    /// <pre>
    ///   企业可通过此接口，根据外部联系人的userid，拉取外部联系人详情。权限说明：
    /// 企业需要使用外部联系人管理secret所获取的accesstoken来调用
    /// 第三方应用需拥有“企业客户”权限。
    /// 第三方应用调用时，返回的跟进人follow_user仅包含应用可见范围之内的成员。
    /// </pre>
    pub async fn get_external_contact(
        &self,
        userid: &str,
    ) -> LabradorResult<WechatCpUserExternalContactInfo> {
        let v = self
            .client
            .get(
                WechatCpMethod::User(CpUserMethod::GetExternalContact(userid.to_string())),
                vec![],
                RequestType::Json,
            )
            .await?
            .json::<Value>()?;
        WechatCommonResponse::parse::<WechatCpUserExternalContactInfo>(v)
    }
}

//----------------------------------------------------------------------------------------------------------------------------
/// 邀请成员的结果对象类
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WxCpTpInviteResponse {
    pub invaliduser: Option<Vec<String>>,
    pub invalidparty: Option<Vec<String>>,
    pub invalidtag: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WxCpTpUseridToOpenidResponse {
    pub openid: Option<String>,
    pub appid: Option<String>,
}
